const W = 100,
  ROW = 6,
  COL = 6,
  SPACE = 10,
  BORDER = W / 20,
  SIDE_W = COL * (W + SPACE) + SPACE + BORDER * 2,
  SIDE_H = ROW * (W + SPACE) + SPACE + BORDER * 2,
  VALUES = ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
  VALUE_COLORS = [
    '#409EFF',
    '#67C23A',
    '#E6A23C',
    '#F56C6C',
    '#B37FEB',
    '#FF85C0',
    '#36CFC9'
  ]

let canvas = document.createElement('canvas')
let ctx = canvas.getContext('2d')

canvas.width = SIDE_W
canvas.height = SIDE_H
canvas.style.cssText =
  'position: absolute; inset: 0; margin: auto; cursor: pointer;'

document.body.appendChild(canvas)
document.body.style.backgroundColor = '#DDDDFF'

let data = Array.from({ length: COL + 2 }, () => Array(ROW + 2).fill(-1))
let s1 = { x: -1, y: -1 },
  s2 = { x: -1, y: -1 }

const checkLine = (p1, p4) => {
  let [x1, y1] = [p1.x, p1.y],
    [x4, y4] = [p4.x, p4.y]
  if (x1 === x4) {
    return data[x1]
      .slice(Math.min(y1, y4) + 1, Math.max(y1, y4))
      .every(v => v === -1)
  } else if (y1 === y4) {
    return data
      .slice(Math.min(x1, x4) + 1, Math.max(x1, x4))
      .every(v => v[y1] === -1)
  } else {
    return false
  }
}

const checkAll = (p1, p4) => {
  let [x1, y1] = [p1.x, p1.y],
    [x4, y4] = [p4.x, p4.y]

  for (let [dx, dy] of [
    [1, 0],
    [0, 1],
    [-1, 0],
    [0, -1]
  ]) {
    let i = 0,
      x2 = x1,
      y2 = y1
    while (data[(x2 = x1 + dx * ++i)]?.[(y2 = y1 + dy * i)] === -1) {
      let p2 = { x: x2, y: y2 },
        p3 = dy === 0 ? { x: x2, y: y4 } : { x: x4, y: y2 }
      if (p3.x === x4 && p3.y === y4 && checkLine(p2, p4)) {
        return true
      }
      if (data[p3.x][p3.y] === -1) {
        if (checkLine(p1, p2) && checkLine(p3, p4)) {
          return true
        }
      }
    }
  }

  return false
}

const check = (p1, p4) => {
  if (p1.x === -1 || p4.x === -1) return false

  if (!(data[p1.x][p1.y] === data[p4.x][p4.y])) return false

  if (checkLine(p1, p4)) return true
  if (checkAll(p1, p4)) return true

  return false
}

const addFocus = (x, y, focusColor = '#00AEEC') => {
  let w = 10
  ctx.strokeStyle = focusColor
  ctx.lineWidth = w
  ctx.strokeRect(trans(x) + w / 2, trans(y) + w / 2, W - w, W - w)
}

const clearFocus = (x, y) => drawBlock(x, y, data[x][y])

canvas.onclick = e => {
  let [x, y] = [e.offsetX, e.offsetY].map(p => Math.ceil(p / (W + SPACE)))
  if (e.offsetX - (x - 1) * (W + SPACE) - BORDER < SPACE) return
  if (e.offsetY - (y - 1) * (W + SPACE) - BORDER < SPACE) return
  if (data[x][y] === -1) return

  let x1 = s1.x,
    y1 = s1.y
  if (x1 === -1 && y1 === -1) {
    s1 = { x, y }
    addFocus(x, y)
  } else {
    if (x1 === x && y1 === y) {
      s1 = { x: -1, y: -1 }
      clearFocus(x, y)
      return
    }

    if (s2.x !== -1 && s2.y !== -1) {
      clearFocus(s2.x, s2.y)
    }
    if (s2.x === x && s2.y === y) {
      s2 = { x: -1, y: -1 }
      return
    }
    s2 = { x, y }
    addFocus(x, y)
  }

  if (check(s1, s2)) {
    data[s1.x][s1.y] = -1
    data[s2.x][s2.y] = -1
    s1 = { x: -1, y: -1 }
    s2 = { x: -1, y: -1 }
    paint()
  }
}

const shuffle = arr => arr.sort(() => Math.random() - 0.5)

const initData = () => {
  let arr = [],
    num = 0
  for (let i = 0; i < (ROW * COL) / 2; i++) {
    num = i % VALUES.length
    arr.push(num, num)
  }
  arr = shuffle(arr)
  for (let i = 1; i <= COL; i++) {
    for (let j = 1; j <= ROW; j++) {
      data[i][j] = arr.pop()
    }
  }
}

const trans = p => (p - 1) * (W + SPACE) + SPACE + BORDER

const drawBlock = (x, y, valIndex) => {
  x = trans(x)
  y = trans(y)
  ctx.fillStyle = VALUE_COLORS[valIndex]
  ctx.fillRect(x, y, W, W)
  ctx.font = '40px serif'
  ctx.fillStyle = '#FFF'
  ctx.textBaseline = 'middle'
  ctx.textAlign = 'center'
  ctx.fillText(VALUES[valIndex], x + W / 2, y + W / 2)
}

const paint = () => {
  ctx.clearRect(0, 0, SIDE_W, SIDE_H)

  for (let i = 1; i <= COL; i++) {
    for (let j = 1; j <= ROW; j++) {
      data[i][j] !== -1 && drawBlock(i, j, data[i][j])
    }
  }
}

const start = () => {
  initData()
  paint()
}

window.onload = start
